From 20f23d9074e5970d4d9dc57669b83d535466bd25 Mon Sep 17 00:00:00 2001 From: Ted Mielczarek Date: Fri, 31 Mar 2017 12:39:19 -0400 Subject: [PATCH] Add support for wrapping cargo's rustc invocations by setting RUSTC_WRAPPER --- src/cargo/util/config.rs | 20 +++++++++++++++----- src/cargo/util/rustc.rs | 18 ++++++++++++++---- src/doc/environment-variables.md | 3 +++ tests/build.rs | 15 +++++++++++++++ tests/cargotest/lib.rs | 3 ++- 5 files changed, 49 insertions(+), 10 deletions(-) diff --git a/src/cargo/util/config.rs b/src/cargo/util/config.rs index 17e909b97..762bc79de 100644 --- a/src/cargo/util/config.rs +++ b/src/cargo/util/config.rs @@ -93,7 +93,8 @@ impl Config { } pub fn rustc(&self) -> CargoResult<&Rustc> { - self.rustc.get_or_try_init(|| Rustc::new(self.get_tool("rustc")?)) + self.rustc.get_or_try_init(|| Rustc::new(self.get_tool("rustc")?, + self.maybe_get_tool("rustc_wrapper")?)) } pub fn cargo_exe(&self) -> CargoResult<&Path> { @@ -415,18 +416,27 @@ impl Config { } } - fn get_tool(&self, tool: &str) -> CargoResult { + /// Look for a path for `tool` in an environment variable or config path, but return `None` + /// if it's not present. + fn maybe_get_tool(&self, tool: &str) -> CargoResult> { let var = tool.chars().flat_map(|c| c.to_uppercase()).collect::(); if let Some(tool_path) = env::var_os(&var) { - return Ok(PathBuf::from(tool_path)); + return Ok(Some(PathBuf::from(tool_path))); } let var = format!("build.{}", tool); if let Some(tool_path) = self.get_path(&var)? { - return Ok(tool_path.val); + return Ok(Some(tool_path.val)); } - Ok(PathBuf::from(tool)) + Ok(None) + } + + /// Look for a path for `tool` in an environment variable or config path, defaulting to `tool` + /// as a path. + fn get_tool(&self, tool: &str) -> CargoResult { + self.maybe_get_tool(tool) + .map(|t| t.unwrap_or(PathBuf::from(tool))) } } diff --git a/src/cargo/util/rustc.rs b/src/cargo/util/rustc.rs index 5bf2e74f3..d401452d7 100644 --- a/src/cargo/util/rustc.rs +++ b/src/cargo/util/rustc.rs @@ -4,6 +4,7 @@ use util::{self, CargoResult, internal, ChainError, ProcessBuilder}; pub struct Rustc { pub path: PathBuf, + pub wrapper: Option, pub verbose_version: String, pub host: String, } @@ -14,12 +15,12 @@ impl Rustc { /// /// If successful this function returns a description of the compiler along /// with a list of its capabilities. - pub fn new(path: PathBuf) -> CargoResult { + pub fn new(path: PathBuf, wrapper: Option) -> CargoResult { let mut cmd = util::process(&path); cmd.arg("-vV"); - + let output = cmd.exec_with_output()?; - + let verbose_version = String::from_utf8(output.stdout).map_err(|_| { internal("rustc -v didn't return utf8 output") })?; @@ -36,12 +37,21 @@ impl Rustc { Ok(Rustc { path: path, + wrapper: wrapper, verbose_version: verbose_version, host: host, }) } pub fn process(&self) -> ProcessBuilder { - util::process(&self.path) + if let Some(ref wrapper) = self.wrapper { + let mut cmd = util::process(wrapper); + { + cmd.arg(&self.path); + } + cmd + } else { + util::process(&self.path) + } } } diff --git a/src/doc/environment-variables.md b/src/doc/environment-variables.md index 97bdb38cb..77bfa7105 100644 --- a/src/doc/environment-variables.md +++ b/src/doc/environment-variables.md @@ -17,6 +17,9 @@ system: relative to the current working directory. * `RUSTC` - Instead of running `rustc`, Cargo will execute this specified compiler instead. +* `RUSTC_WRAPPER` - Instead of simply running `rustc`, Cargo will execute this + specified wrapper instead, passing as its commandline arguments the rustc + invocation, with the first argument being rustc. * `RUSTDOC` - Instead of running `rustdoc`, Cargo will execute this specified `rustdoc` instance instead. * `RUSTFLAGS` - A space-separated list of custom flags to pass to all compiler diff --git a/tests/build.rs b/tests/build.rs index fa92dadff..62018406f 100644 --- a/tests/build.rs +++ b/tests/build.rs @@ -2899,3 +2899,18 @@ fn run_proper_binary_main_rs_as_foo() { assert_that(p.cargo_process("run").arg("--bin").arg("foo"), execs().with_status(0)); } + +#[test] +fn rustc_wrapper() { + // We don't have /usr/bin/env on Windows. + if cfg!(windows) { return } + + let p = project("foo") + .file("Cargo.toml", &basic_bin_manifest("foo")) + .file("src/foo.rs", &main_file(r#""i am foo""#, &[])); + + assert_that(p.cargo_process("build").arg("-v").env("RUSTC_WRAPPER", "/usr/bin/env"), + execs().with_stderr_contains( + "[RUNNING] `/usr/bin/env rustc --crate-name foo [..]") + .with_status(0)); +} diff --git a/tests/cargotest/lib.rs b/tests/cargotest/lib.rs index a4410a853..15dc956ca 100644 --- a/tests/cargotest/lib.rs +++ b/tests/cargotest/lib.rs @@ -27,7 +27,7 @@ use std::env; pub mod support; pub mod install; -thread_local!(pub static RUSTC: Rustc = Rustc::new(PathBuf::from("rustc")).unwrap()); +thread_local!(pub static RUSTC: Rustc = Rustc::new(PathBuf::from("rustc"), None).unwrap()); pub fn rustc_host() -> String { RUSTC.with(|r| r.host.clone()) @@ -54,6 +54,7 @@ fn _process(t: &OsStr) -> cargo::util::ProcessBuilder { .env_remove("__CARGO_DEFAULT_LIB_METADATA") .env_remove("RUSTC") .env_remove("RUSTDOC") + .env_remove("RUSTC_WRAPPER") .env_remove("RUSTFLAGS") .env_remove("CARGO_INCREMENTAL") .env_remove("XDG_CONFIG_HOME") // see #2345 -- 2.30.2